package org.xlp.mvc.context;

import org.xlp.bean.base.IBeanDefinition;
import org.xlp.bean.base.IBeansContainer;
import org.xlp.bean.exception.BeanBaseException;
import org.xlp.bean.exception.BeanDefinitionExistException;
import org.xlp.bean.exception.BeanExistException;
import org.xlp.bean.exception.NotSuchBeanException;
import org.xlp.bean.impl.DefaultBeansContainer;

import java.lang.reflect.Type;

/**
 * @author xlp
 * created by xlp 20230828
 * 上下文容器
 */
public abstract class AbstractApplicationContext extends DefaultBeansContainer implements IBeansContainer {
    /**
     * 类加载器
     */
    private ClassLoader classLoader;

    /**
     * bean容器，用来管理bean
     */
    private IBeansContainer beansContainer;

    /**
     * 要扫描的包路径
     */
    protected String[] packages;

    /**
     * 构造函数
     */
    public AbstractApplicationContext(){
        this.beansContainer = new DefaultBeansContainer();
    }

    /**
     * 构造函数
     * @param classLoader
     */
    public AbstractApplicationContext(ClassLoader classLoader){
        this();
        this.classLoader = classLoader;
    }

    /**
     * 构造函数
     * @param classLoader
     * @param packages 要扫描的包路径
     */
    public AbstractApplicationContext(ClassLoader classLoader, String[] packages){
        this(classLoader);
        this.packages = packages;
    }

    /**
     * 构造函数
     * @param packages 要扫描的包路径
     */
    public AbstractApplicationContext(String[] packages){
        this();
        this.packages = packages;
    }

    /**
     * 构造函数
     * @param beansContainer
     */
    public AbstractApplicationContext(IBeansContainer beansContainer){
        this();
        this.beansContainer = beansContainer;
    }

    /**
     * 构造函数
     * @param beansContainer
     * @param classLoader
     */
    public AbstractApplicationContext(IBeansContainer beansContainer, ClassLoader classLoader){
        this(beansContainer);
        this.classLoader = classLoader;
    }

    /**
     * 构造函数
     * @param beansContainer
     * @param classLoader
     * @param packages
     */
    public AbstractApplicationContext(IBeansContainer beansContainer, ClassLoader classLoader, String[] packages){
        this(beansContainer, classLoader);
        this.packages = packages;
    }

    /**
     * 获取bean管理容器
     * @return
     */
    public IBeansContainer getBeansContainer() {
        return beansContainer == null ? new DefaultBeansContainer() : beansContainer;
    }

    /**
     * 获取类加载器
     * @return
     */
    public ClassLoader getClassLoader() {
        return classLoader;
    }

    /**
     * 获取要扫描的吧路径
     * @return
     */
    public String[] getPackages() {
        return packages == null ? new String[0] : packages;
    }

    /**
     * 向容器中添加bean定义对象
     *
     * @param beanDefinition bean定义对象
     * @param covering       是否覆盖已有的bean定义，true；是  false: 否
     * @throws BeanDefinitionExistException 假如容器中存在并且<dode>covering is false</dode>，则抛出该异常
     */
    @Override
    public void addBeanDefinition(IBeanDefinition beanDefinition, boolean covering) throws BeanDefinitionExistException {
        getBeansContainer().addBeanDefinition(beanDefinition, covering);
    }

    /**
     * 向容器中添加指定类型的bean定义对象
     *
     * @param beanClass bean定义对象
     * @param covering  是否覆盖已有的bean定义，true；是  false: 否
     * @throws BeanDefinitionExistException 假如容器中存在并且<dode>covering is false</dode>，则抛出该异常
     */
    @Override
    public void addBeanDefinition(Class<?> beanClass, boolean covering) throws BeanDefinitionExistException {
        getBeansContainer().addBeanDefinition(beanClass, covering);
    }

    /**
     * 判断bean定义已在容器中存在的类型
     *
     * @param beanDefinition
     * @return
     */
    @Override
    public BeanDefinitionExistType judgeBeanDefinition(IBeanDefinition beanDefinition) {
        return getBeansContainer().judgeBeanDefinition(beanDefinition);
    }

    /**
     * 向容器中添加指定ID的bean对象
     *
     * @param bean
     * @param beanId
     * @param covering 是否覆盖已有的bean定义，true；是  false: 否
     * @param types    对应的泛型信息
     * @throws BeanExistException 假如容器中存在并且<dode>covering is false</dode>，则抛出该异常
     */
    @Override
    public <T> void addBean(T bean, String beanId, boolean covering, Class<?>... types) throws BeanExistException {
        getBeansContainer().addBean(bean, beanId, covering, types);
    }

    /**
     * 向容器中添加指定类型的bean
     *
     * @param bean
     * @param beanClass
     * @param covering  是否覆盖已有的bean定义，true；是  false: 否
     * @param types     对应的泛型信息
     * @throws BeanExistException 假如容器中存在并且<dode>covering is false</dode>，则抛出该异常
     */
    @Override
    public <T> void addBean(T bean, Class<? super T> beanClass, boolean covering, Class<?>... types) throws BeanExistException {
        getBeansContainer().addBean(bean, beanClass, covering, types);
    }

    /**
     * 重置容器中的数据
     */
    @Override
    public void reset() {
        getBeansContainer().reset();
    }

    /**
     * 判断给的id的bean是否被代理
     *
     * @param id bean id
     * @throws NotSuchBeanException 假如未找到指定id的bean则抛出该异常
     */
    @Override
    public boolean isProxy(String id) throws NotSuchBeanException {
        return getBeansContainer().isProxy(id);
    }

    /**
     * 判断给的类型的bean是否被代理
     *
     * @param beanClass bean类型
     * @return true: 是，false：否
     * @throws NotSuchBeanException 假如未找到指定类名的bean则抛出该异常
     */
    @Override
    public <T> boolean isProxy(Class<T> beanClass) throws NotSuchBeanException {
        return getBeansContainer().isProxy(beanClass);
    }

    /**
     * 判断给的id的bean是否是单例
     *
     * @param id bean id
     * @return true: 是，false：否
     * @throws NotSuchBeanException 假如未找到指定id的bean则抛出该异常
     */
    @Override
    public boolean isSingleton(String id) throws NotSuchBeanException {
        return getBeansContainer().isSingleton(id);
    }

    /**
     * 判断给的类型的bean是否是单例
     *
     * @param beanClass bean类型
     * @return true: 是，false：否
     * @throws NotSuchBeanException 假如未找到指定id的bean则抛出该异常
     */
    @Override
    public <T> boolean isSingleton(Class<T> beanClass) throws NotSuchBeanException {
        return getBeansContainer().isSingleton(beanClass);
    }

    /**
     * 判断给的id的bean是否延迟实例化
     *
     * @param id bean id
     * @return true: 是，false：否
     * @throws NotSuchBeanException 假如未找到指定id的bean则抛出该异常
     */
    @Override
    public boolean isLazy(String id) throws NotSuchBeanException {
        return getBeansContainer().isLazy(id);
    }

    /**
     * 判断给的类型的bean是否延迟实例化
     *
     * @param beanClass bean类型
     * @return true: 是，false：否
     * @throws NotSuchBeanException 假如未找到指定id的bean则抛出该异常
     */
    @Override
    public <T> boolean isLazy(Class<T> beanClass) throws NotSuchBeanException {
        return getBeansContainer().isLazy(beanClass);
    }

    /**
     * 获取该id的bean对象
     *
     * @param id bean id
     * @return bean 对象
     * @throws BeanBaseException 假如或bean过程失败，则抛出该异常
     */
    @Override
    public <T> T getBean(String id) throws BeanBaseException {
        return getBeansContainer().getBean(id);
    }

    /**
     * 获取该id的bean对象
     *
     * @param beanClass bean类型
     * @return bean 对象
     * @throws BeanBaseException 假如或bean过程失败，则抛出该异常
     */
    @Override
    public <T, I> T getBean(Class<I> beanClass) throws BeanBaseException {
        return getBeansContainer().getBean(beanClass);
    }

    /**
     * 获取该id的bean对象
     *
     * @param beanClass bean类型
     * @param types     目标泛型类型
     * @return bean 对象
     * @throws BeanBaseException 假如或bean过程失败，则抛出该异常
     */
    @Override
    public <T, I> T getBean(Class<I> beanClass, Type[] types) throws BeanBaseException {
        return getBeansContainer().getBean(beanClass, types);
    }

    /**
     * 获取指定类型待泛型目标类型的Bean对象
     *
     * @param beanClass bean类型
     * @param types     泛型目标类型
     * @return
     * @throws BeanBaseException 假如或bean过程失败，则抛出该异常
     */
    @Override
    public <T> T getBean(Class<?> beanClass, Class<?>... types) {
        Type[] _types = new Type[types == null ? 0 : types.length];
        for (int i = 0, len = _types.length; i < len; i++) {
            _types[i] = types[i];
        }
        return getBean(beanClass, _types);
    }

    /**
     * 获取该类全路径名称的bean对象
     *
     * @param className 类全路径名称
     * @return bean 对象
     * @throws BeanBaseException 假如或bean过程失败，则抛出该异常
     */
    @Override
    public <T> T getBeanByClassName(String className) throws BeanBaseException {
        return getBeansContainer().getBeanByClassName(className);
    }

    /**
     * 创建出所有的单例非延迟加载的bean对象
     */
    @Override
    public void createBeans() {
        getBeansContainer().createBeans();
    }

    /**
     * 设置bean创建容器
     * @param beansContainer
     */
    protected void setBeansContainer(IBeansContainer beansContainer) {
        this.beansContainer = beansContainer;
    }

    /**
     * 完成创建上下文对象
     * @return
     */
    public abstract AbstractApplicationContext complete() throws ApplicationContextException;

}
